package ldh.serialize.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ClassInfo {

	private Set<ClassData> datas;
	
	private Class<?> clazz;
	
	public ClassInfo(Class<?> clazz) {
		this.clazz = clazz;
		init();
	}

	public Set<ClassData> getDatas() {
		return datas;
	}

	public void setDatas(Set<ClassData> datas) {
		this.datas = datas;
	}

	public Class<?> getClazz() {
		return clazz;
	}

	public void setClazz(Class<?> clazz) {
		this.clazz = clazz;
	}

	public static <T>T newClazz(Class<T> clazz) {
		Constructor con;
		try {
			if (clazz.isPrimitive() || clazz == String.class) {
				return null;
			}
			con = clazz.getConstructor();
			return (T) con.newInstance();
		} catch (Exception e) {
			return null;
//			throw new RuntimeException(clazz + "无构造函数", );
		}

	}

	private void init() {
		Set<Field> fields = SerializedUtil.getAllFields(clazz);
		Set<Method> methods = SerializedUtil.getAllMethods(clazz);
		
		datas = new HashSet<ClassData>();
		
		if (fields != null) {
			for (Field field : fields) {
//				if (field.getAnnotation(Transient.class) != null) {
//					continue;
//				}
				if (field.getModifiers() == Modifier.STATIC) {
					continue;
				}
				Method[] ms = getMethods(field, methods);
				if (ms != null) {
					datas.add(new ClassData(field, ms[0], ms[1]));
				}
			}
		}
		
	}
	
	private Method[] getMethods(Field field, Set<Method> methods) {
		String name = field.getName();
		String tt = name.substring(0, 1).toUpperCase() + name.substring(1);
		String getMethodName = "get" + tt;
		String setMethodName = "set" + tt;
		Class<?> type = field.getType();
		Method readMethod = null;
		Method writeMethod = null;
		for (Method m : methods) {
			if (m.getReturnType() == type && m.getName().equals(getMethodName)) {
				readMethod = m;
			} else if (m.getParameterTypes().length == 1 && m.getParameterTypes()[0] == type && m.getName().equals(setMethodName)) {
				writeMethod = m;
			}
		}
		
		return readMethod != null && writeMethod != null ? new Method[]{ readMethod, writeMethod} : null;
	}
	
	
	public static class ClassData {
		private String property;
		private Field field;
		private Method readMethod;
		private Method writeMethod;
		
		public ClassData(Field field, Method readMethod, Method writeMethod) {
			this.field = field;
			this.readMethod = readMethod;
			this.writeMethod = writeMethod;
			this.property = field.getName();
		}
		
		public String getProperty() {
			return property;
		}
		
		public void setProperty(String property) {
			this.property = property;
		}
		
		public Field getField() {
			return field;
		}

		public void setField(Field field) {
			this.field = field;
		}

		public Method getReadMethod() {
			return readMethod;
		}
		
		public void setReadMethod(Method readMethod) {
			this.readMethod = readMethod;
		}
		
		public Method getWriteMethod() {
			return writeMethod;
		}
		
		public void setWriteMethod(Method writeMethod) {
			this.writeMethod = writeMethod;
		}
		
		public String getJavaType() {
			Class<?> clazz = field.getType();
			if (field.getType().isPrimitive()) {
				clazz = TransferUtil.convert(clazz);
				return clazz.getSimpleName();
			} else if (Iterable.class.isAssignableFrom(clazz)) {
				Class<?> param = TransferUtil.getIterableParam(field.getGenericType());
				if (param == null) {
					return clazz.getSimpleName();
				}
				return clazz.getSimpleName() + "<" + param.getSimpleName() + ">";
			} else if (Map.class.isAssignableFrom(clazz)) {
				Class<?>[] ps = TransferUtil.getMapParam(field.getGenericType());
				if (ps != null) {
					return clazz.getSimpleName() + "<" + ps[0].getSimpleName() + ", " + ps[1].getSimpleName() + ">";
				}
				return clazz.getSimpleName();
			}
			
			return clazz.getSimpleName();
		}
		
		public String getSimpleJavaType() {
			Class<?> clazz = field.getType();
			if (field.getType().isPrimitive()) {
				clazz = TransferUtil.convert(clazz);
			} else if (clazz.isArray()) {
				return clazz.getComponentType().getSimpleName();
			}
			return clazz.getSimpleName();
		}
		
		

	}
}
